/*
 * Copyright (c) 2020-2021, SERI Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date             Author      Notes
 * 2021-10-29       Lyons       first version
 * 2022-04-04       Lyons       v2.0
 */

`ifdef TESTBENCH_VCS
`include "pa_chip_param.v"
`else
`include "../pa_chip_param.v"
`endif

module pa_perips_tcm (
    input  wire                         clk_i,
    input  wire                         rst_n_i,

    input  wire [`ADDR_BUS_WIDTH-1:0]   addr1_i,
    input  wire                         rd1_i,
    input  wire                         we1_i,
    input  wire [2:0]                   size1_i,
    input  wire [`DATA_BUS_WIDTH-1:0]   data1_i,
    output wire [`DATA_BUS_WIDTH-1:0]   data1_o,

    input  wire [`ADDR_BUS_WIDTH-1:0]   addr2_i,
    input  wire                         rd2_i,
    output wire [`DATA_BUS_WIDTH-1:0]   data2_o
);


wire [`ADDR_BUS_WIDTH-1:0]              index1;
wire [`ADDR_BUS_WIDTH-1:0]              index2;

assign index1[`ADDR_BUS_WIDTH-1:0] = {2'b0, 4'b0, addr1_i[27:2]};
assign index2[`ADDR_BUS_WIDTH-1:0] = {2'b0, 4'b0, addr2_i[27:2]};

reg  [3:0]                              addr_mask;

wire                                    size_word;
wire                                    size_half;

assign size_word = size1_i[2];
assign size_half = size1_i[1];

always @ (*) begin
case (addr1_i[1:0])
    2'b00 : addr_mask[3:0] <= {size_word, size_word, (size_word || size_half), 1'b1};
    2'b01 : addr_mask[3:0] <= {4'b0010};
    2'b10 : addr_mask[3:0] <= {size_half, 3'b100};
    2'b11 : addr_mask[3:0] <= {4'b1000};
endcase
end


wire [`DATA_BUS_WIDTH-1:0]              _data1;
wire [`DATA_BUS_WIDTH-1:0]              _data2;

Gowin_DPB_8x4k _ram_3 (
    .douta(_data1[31:24]), //output [7:0] douta
    .doutb(_data2[31:24]), //output [7:0] doutb
    .clka(clk_i), //input clka
    .ocea(`VALID), //input ocea
    .cea(`VALID), //input cea
    .reseta(~rst_n_i), //input reseta
    .wrea(we1_i && addr_mask[3]), //input wrea
    .clkb(clk_i), //input clkb
    .oceb(`VALID), //input oceb
    .ceb(`VALID), //input ceb
    .resetb(~rst_n_i), //input resetb
    .wreb(1'b0), //input wreb
    .ada(addr1_i[13:2]), //input [11:0] ada
    .dina(data1_i[31:24]), //input [7:0] dina
    .adb(addr2_i[13:2]), //input [11:0] adb
    .dinb(8'b0) //input [7:0] dinb
);

Gowin_DPB_8x4k _ram_2 (
    .douta(_data1[23:16]), //output [7:0] douta
    .doutb(_data2[23:16]), //output [7:0] doutb
    .clka(clk_i), //input clka
    .ocea(`VALID), //input ocea
    .cea(`VALID), //input cea
    .reseta(~rst_n_i), //input reseta
    .wrea(we1_i && addr_mask[2]), //input wrea
    .clkb(clk_i), //input clkb
    .oceb(`VALID), //input oceb
    .ceb(`VALID), //input ceb
    .resetb(~rst_n_i), //input resetb
    .wreb(1'b0), //input wreb
    .ada(addr1_i[13:2]), //input [11:0] ada
    .dina(data1_i[23:16]), //input [7:0] dina
    .adb(addr2_i[13:2]), //input [11:0] adb
    .dinb(8'b0) //input [7:0] dinb
);

Gowin_DPB_8x4k _ram_1 (
    .douta(_data1[15:8]), //output [7:0] douta
    .doutb(_data2[15:8]), //output [7:0] doutb
    .clka(clk_i), //input clka
    .ocea(`VALID), //input ocea
    .cea(`VALID), //input cea
    .reseta(~rst_n_i), //input reseta
    .wrea(we1_i && addr_mask[1]), //input wrea
    .clkb(clk_i), //input clkb
    .oceb(`VALID), //input oceb
    .ceb(`VALID), //input ceb
    .resetb(~rst_n_i), //input resetb
    .wreb(1'b0), //input wreb
    .ada(addr1_i[13:2]), //input [11:0] ada
    .dina(data1_i[15:8]), //input [7:0] dina
    .adb(addr2_i[13:2]), //input [11:0] adb
    .dinb(8'b0) //input [7:0] dinb
);

Gowin_DPB_8x4k _ram_0 (
    .douta(_data1[7:0]), //output [7:0] douta
    .doutb(_data2[7:0]), //output [7:0] doutb
    .clka(clk_i), //input clka
    .ocea(`VALID), //input ocea
    .cea(`VALID), //input cea
    .reseta(~rst_n_i), //input reseta
    .wrea(we1_i && addr_mask[0]), //input wrea
    .clkb(clk_i), //input clkb
    .oceb(`VALID), //input oceb
    .ceb(`VALID), //input ceb
    .resetb(~rst_n_i), //input resetb
    .wreb(1'b0), //input wreb
    .ada(addr1_i[13:2]), //input [11:0] ada
    .dina(data1_i[7:0]), //input [7:0] dina
    .adb(addr2_i[13:2]), //input [11:0] adb
    .dinb(8'b0) //input [7:0] dinb
);


assign data1_o[`DATA_BUS_WIDTH-1:0] = _data1[`DATA_BUS_WIDTH-1:0];
assign data2_o[`DATA_BUS_WIDTH-1:0] = _data2[`DATA_BUS_WIDTH-1:0];

endmodule
